package com.shujia

import java.util
import scala.collection.mutable.ListBuffer
import scala.io.{BufferedSource, Source}

object Demo09List {
  def main(args: Array[String]): Unit = {
    /**
     * List列表特点：有序，元素可以重复，一般情况下元素的类型都一致，不可变
     */

    // 定义一个List，泛型可以省略
    val list1: List[Int] = List[Int](1, 2, 2, 9, 8, 7, 3, 4, 5, 6)
    // 可以通过下标取元素 ===> 有序 ，但是不能修改
    println(list1(0))
    //    list1(0) = 11

    /**
     * List中常见的方法
     */

    println(list1.max)
    println(list1.min)
    println(list1.sum)
    println(list1.size)
    println(list1.head)
    println(list1.tail)
    println(list1.last)
    println(list1.take(2))
    println(list1.sorted)
    println(list1.contains(2))
    println(list1.contains(20))
    println(list1.isEmpty)
    println(list1.nonEmpty)

    /**
     * 高级方法：
     * 常用：map、flatMap、foreach、filter、groupBy
     * 不常用：sortWith、sortBy
     */

    val strList: List[String] = List[String]("hadoop,hive,hbase", "java,scala,python", "java,scala,python", "java,scala,python")

    strList
      .flatMap((line: String) => {
        line.split(",")
      })
      .groupBy((word: String) => {
        word
      })
      .map((t2: (String, List[String])) => {
        val word: String = t2._1
        val cnt: Int = t2._2.size
        s"$word,$cnt"
      })
      .foreach(println)

    /**
     * map VS foreach
     * 主要区别：有无返回值
     * 怎么选？
     * 两者都能对数据进行逐行（逐个）遍历，主要看遍历完之后还需不需要做后续处理
     * 如果直接打印输出或者保存到外部系统，不需要后续处理则选择foreach
     * 如果遍历完之后还需要进一步处理，则选择map
     *
     * flatMap：类似SQL中的explode函数
     * 可以将数据容器中的每一个元素进行扁平化处理（展开）
     * flatMap需要接受一个函数f
     * 函数f的返回值类型为GenTraversableOnce
     * GenTraversableOnce：Scala中的集合类、Array数组都属于该范畴
     * 实际上只要传入的函数f返回的是List、Set、Map、Tuple、Array
     * 那么flatMap都可以对结果进行展开处理
     */

    strList
      .flatMap((line: String) => {
        line.split(",")
      }).foreach(println)

    // 简写
    strList
      .flatMap(_.split(",")).foreach(println)

    /**
     * filter：主要用于过滤
     * 同样需要接收一个函数p
     * 函数p的返回值类型需要是Boolean类型
     * 即：
     * 如果返回值是true，则保留数据
     * 如果返回值时false，则过滤数据
     *
     */
    println(list1)
    // 将奇数过滤出来
    list1.filter(i => i % 2 == 1).foreach(println)

    // 将偶数过滤出来
    list1.filter(i => i % 2 == 0).foreach(println)

    /**
     * groupBy：用于分组，聚合方式自己实现
     * 需要指定一个分组“字段”，
     * 最终得到的每一条数据都是一个二元组
     * 二元组的第一个元素就是指定的分组字段
     * 二元组的第二个元素就是属于同一组的所有的数据构成的一个List集合
     */
    // 1、统计班级人数 [班级,人数]

    // 读文件
    val stuBS: BufferedSource = Source.fromFile("scala/data/students.txt")

    // 加载数据
    val stuList: List[String] = stuBS.getLines().toList

    // 切分每一行数据 提取班级列
    val clazzList: List[(String, Int)] = stuList.map((line: String) => {
      (line.split(",")(4), 1)
    })

    clazzList.foreach(println)

    // 按照班级分组
    val grp: List[(String, List[(String, Int)])] = clazzList
      .groupBy(t2 => {
        t2._1
      }).toList

    // 统计每个班级的人数
    val clazzCnt: List[String] = grp.map(t2 => {
      val clazz: String = t2._1
      val cnt: Int = t2._2.size
      s"$clazz,$cnt"
    })

    // 打印
    clazzCnt.foreach(println)

    /**
     * sortBy：指定一个“字段”进行排序
     */

    val stuCaseList: List[StuList] = stuList.map(line => {
      val splits: Array[String] = line.split(",")
      StuList(splits(0), splits(1), splits(2).toInt, splits(3), splits(4))
    })

    // 按照年龄进行排序(默认升序)
    stuCaseList.sortBy(s => s.age)
    //      .foreach(println)
    stuCaseList.sortBy(s => -s.age)
    //      .foreach(println) // 降序排列

    /**
     * sortWith：指定一个排序规则
     */

    stuCaseList.sortWith((s1, s2) => {
      // 定义一个排序规则
      if (s1.age == s2.age) {
        if (s1.gender == s2.gender) {
          s1.clazz < s2.clazz
        } else {
          s1.gender < s2.gender
        }
      } else {
        s1.age < s2.age
      }
    }).foreach(println)

    // 可变的List：ListBuffer
    // 使用起来同List一致，但是会比List多一些增删改操作
    val listBuffer: ListBuffer[Int] = ListBuffer[Int](1, 2, 2, 3, 3, 3, 4, 5, 9, 6, 8, 7)

    println(listBuffer.max)
    println(listBuffer.min)
    println(listBuffer.sum)
    println(listBuffer.size)
    println(listBuffer.head)
    println(listBuffer.tail)
    println(listBuffer.last)
    println(listBuffer.take(2))
    println(listBuffer.sorted)
    println(listBuffer.contains(2))
    println(listBuffer.contains(20))
    println(listBuffer.isEmpty)
    println(listBuffer.nonEmpty)

    println(listBuffer)
    // 增加元素
    listBuffer.append(11, 10) // 追加
    println(listBuffer)
    listBuffer.+=(100)
    listBuffer += 100
    println(listBuffer)

    listBuffer.insert(3, 23) // 指定位置添加
    println(listBuffer)

    // 修改元素
    listBuffer.update(3, 32)
    println(listBuffer)
    listBuffer(0) = 11 // 通过下标进行修改
    println(listBuffer)


    // 删除元素
    listBuffer.remove(4, 2) // 指定位置进行删除
    println(listBuffer)
    listBuffer.-=(32) // 指定元素进行删除
    println(listBuffer)



  }

  case class StuList(id: String, name: String, age: Int, gender: String, clazz: String)

}
